package com.dz.finance.biz.service.impl;

import com.dz.finance.biz.config.ObjectConvertor;
import com.dz.finance.biz.constant.RedisKeyConstant;
import com.dz.finance.biz.dto.CreateMenuDTO;
import com.dz.finance.biz.entity.SysMenu;
import com.dz.finance.biz.mapper.SysMenuMapper;
import com.dz.finance.biz.service.SysMenuService;
import com.dz.finance.biz.vo.ListTreeMenuVo;
import com.dz.finance.common.entity.User;
import com.dz.finance.common.exception.BizException;
import com.dz.finance.common.service.UserTokenService;
import com.dz.finance.common.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;


/**
 * @author: DengHaoQi
 * @date: 2024/7/3 15:20
 * @description:
 */


@Slf4j
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl implements SysMenuService {

    private final RedissonClient redissonClient;
    private final SysMenuMapper sysMenuMapper;
    private final UserTokenService<User> userTokenService;
    private final ObjectConvertor objectConvertor;

    /*
     * 创建菜单
     * */
    @Override
    public boolean create(CreateMenuDTO dto) {

        RLock rLock = redissonClient.getLock(RedisKeyConstant.CHANGE_MENU_LOCK);
        try {
            rLock.lock();
            // 检查父级菜单
            int level = checkParentMenu(dto.getPid());

            // 构造db对象
            SysMenu sysMenu = SysMenu.builder()
                    .pid(dto.getPid())
                    .memberId(userTokenService.getThreadLocalUserId())
                    .name(dto.getName())
                    .path(dto.getPath())
                    .component(dto.getComponent())
                    .icon(dto.getIcon())
                    .layout(dto.getLayout() ? 0 : 1)
                    .hideInMenu(dto.getHideInMenu() ? 0 : 1)
                    .redirect(dto.getRedirect())
                    .sort(dto.getSort())
                    .nodePath(level + 1)
                    .disable(0)
                    .createTime(DateUtils.getSystemTime())
                    .updateTime(DateUtils.getSystemTime())
                    .updateMemberId(userTokenService.getThreadLocalUserId())
                    .delFlag(0)
                    .build();
            int row = sysMenuMapper.insert(sysMenu);
            return row > 0;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BizException(e.getMessage(), e);
        } finally {
            rLock.unlock();
        }
    }


    /*
     * 查询树形菜单列表
     * */
    @Override
    public List<ListTreeMenuVo> getTreeMenuList(String name) {
        if (Strings.isNotBlank(name)) {
            // 模糊查询
            List<SysMenu> listByName = sysMenuMapper.selectListByName(name);
            return objectConvertor.toTreeMenuVo(listByName);
        }
        return buildTreeList(objectConvertor.toTreeMenuVo(sysMenuMapper.selectList()), 0);
    }


    private List<ListTreeMenuVo> buildTreeList(List<ListTreeMenuVo> list, int pid) {
        List<ListTreeMenuVo> buildTree = new ArrayList<>();
        for (ListTreeMenuVo listTreeMenuVo : list) {
            if (listTreeMenuVo.getPid() == pid) {
                listTreeMenuVo.setChildren(buildTreeList(list, listTreeMenuVo.getPid()));
                buildTree.add(listTreeMenuVo);
            }
        }
        return buildTree;
    }

    /*
     * 检测父级菜单，返回结点深度
     * */
    private int checkParentMenu(Integer pid) {
        if (pid == 0) {
            return 0;
        }
        SysMenu condition = new SysMenu();
        condition.setId(pid);
        SysMenu sysMenu = sysMenuMapper.selectSysMenu(condition);
        if (sysMenu == null) {
            throw new BizException("父级菜单不存在");
        }
        if (sysMenu.getPid() > 0) {
            throw new BizException("不可以创建三级菜单");
        }
        return sysMenu.getNodePath();
    }

}
